home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1994 November: Tool Chest / Dev.CD Nov 94.toast / Sample Code / Snippets / QuickDraw / Restore Screen Cluts / ColorReset.c next >
Encoding:
C/C++ Source or Header  |  1992-07-15  |  44.8 KB  |  1,281 lines  |  [TEXT/MPS ]

  1. /******************************************************************************\
  2. *
  3. * Apple Macintosh Developer Technical Support
  4. *
  5. * Main program file
  6. *
  7. * Program: ColorImage
  8. * File:    ColorImage.c
  9. *
  10. * by:      Forrest Tanaka
  11. *
  12. * Copyright © 1988-1992 Apple Computer, Inc.
  13. * All rights reserved.
  14. *
  15. \******************************************************************************/
  16.  
  17.  
  18. /******************************************************************************\
  19. * Header Files
  20. \******************************************************************************/
  21.  
  22. #ifndef THINK_C
  23. #include <Desk.h>
  24. #include <DiskInit.h>
  25. #include <Errors.h>
  26. #include <Fonts.h>
  27. #include <Menus.h>
  28. #include <Resources.h>
  29. #include <ToolUtils.h>
  30. #endif
  31.  
  32. #include <AppleEvents.h>
  33. #include <GestaltEqu.h>
  34. #include <Packages.h>
  35. #include <Palettes.h>
  36. #include <Traps.h>
  37.  
  38. #include "EmergMem.h"
  39. #include "Exceptions.h"
  40. #include "ColorReset.h"
  41. #include "MenuHandler.h"
  42. #include "PictDocument.h"
  43. #include "WindowPositioner.h"
  44.  
  45.  
  46. /******************************************************************************\
  47. * Constants
  48. \******************************************************************************/
  49.  
  50. /* Disk initialization */
  51. #define kSysAlertLeft 80 /* Left coord of DIBadMount alert in screen coords */
  52. #define kSysAlertTop  80 /* Top coord of DIBadMount alert in screen coords */
  53.  
  54. /* EqualString convenience constants */
  55. #define kCaseSens true /* Pass to EqualString for case-sensitive check */
  56. #define kDiacSens true /* Pass to EqualString for diacritical-sens. check */
  57.  
  58. /* Constants for checking on command-. */
  59. #define kMaskModifiers 0xFE00     /* Mask for modifiers w/o command key */
  60. #define kMaskASCII1    0x00FF0000 /* get the key out of the ASCII1 byte */
  61. #define kMaskASCII2    0x000000FF /* get the key out of the ASCII2 byte */
  62.  
  63. /* Miscellaneous */
  64. #define kMinWindSize    128  /* Minimum size of a window */
  65. #define kMaxSleepTime   60   /* # ticks to wait between minor switches */
  66. #define kBecomingActive true /* Pass to DoActivateEvt; app becoming active */
  67.  
  68.  
  69. /******************************************************************************\
  70. * Macros
  71. \******************************************************************************/
  72.  
  73. /* Return status of bth bit of m */
  74. #define btst(m,b) ((m) & (1L << (b)))
  75.  
  76.  
  77. /******************************************************************************\
  78. * Global Variables
  79. \******************************************************************************/
  80.  
  81. Boolean gHasWNE;         /* True if WaitNextEvent is implemented */
  82. Boolean gQuitting;       /* True if user requested that this app quit */
  83. Boolean gWereInFront;    /* True if this application is frontmost */
  84. Boolean gFixMenus;       /* True if menus need fixing */
  85. Boolean gHasAppleEvents; /* True if Apple Events implemented */
  86. Boolean gHasCoolSF;      /* True if 7.0 Standard File routines available */
  87.  
  88.  
  89. /******************************************************************************\
  90. * Private Function Prototypes
  91. \******************************************************************************/
  92.  
  93. int main(void);
  94.  
  95. void StartUp(void);
  96.  
  97. void ShutDown(void);
  98.  
  99. void EventLoop(void);
  100.  
  101. long CalcSleepTime(void);
  102.  
  103. void DoMouseDown(
  104.     EventRecord *anEvent);
  105.  
  106. void DoKeyDown(
  107.     EventRecord *anEvent);
  108.  
  109. void DoDiskEvt(
  110.     EventRecord *anEvent);
  111.  
  112. pascal OSErr HandleAEquit(
  113.     AppleEvent *quitAppleEvent,
  114.     AppleEvent *reply,
  115.     long       handlerRefCon);
  116.  
  117. OSErr DoneRequiredParams(
  118.     AppleEvent *anAppleEvent);
  119.  
  120. Boolean IsDAWindow(
  121.     WindowPtr aWindow);
  122.  
  123. void DoWindowDrag(
  124.     EventRecord *anEvent,
  125.     WindowPtr   clickedWindow);
  126.  
  127. void DoWindowGrow(
  128.     EventRecord *anEvent,
  129.     WindowPtr   clickedWindow);
  130.  
  131. void DoContentClick(
  132.     EventRecord *anEvent,
  133.     WindowPtr   clickedWindow);
  134.  
  135. void DoActivateEvt(
  136.     WindowPtr eventWind,
  137.     Boolean   becomingActive);
  138.  
  139. void DoWindowClose(
  140.     EventRecord *anEvent,
  141.     WindowPtr   eventWindow);
  142.  
  143. short MaxToolboxTrap(void);
  144.  
  145. TrapType GetTrapType(
  146.     short theTrap);
  147.  
  148.  
  149. /******************************************************************************\
  150. * Public: main - Entry point to this application
  151. *
  152. * After the heap is initialized by allocating several master pointer blocks and
  153. * expanding the application’s heap to its maximum size, StartUp is called to
  154. * complete initialization.  The user is asked to open a Picture Document, and
  155. * then the main event loop is entered.
  156. \******************************************************************************/
  157.  
  158. int main()
  159. {
  160.     /* Prepare the heap */
  161.     MaxApplZone();
  162.     MoreMasters();
  163.     MoreMasters();
  164.     MoreMasters();
  165.     MoreMasters();
  166.     MoreMasters();
  167.     MoreMasters();
  168.     MoreMasters();
  169.     MoreMasters();
  170.  
  171.     /* Initialize the application */
  172.     StartUp();
  173.  
  174.     /* Ask the user for a Picture Document to open */
  175.     (void)DoOpenPictDoc();
  176.  
  177.     /* Execute the main event loop */
  178.     EventLoop();
  179.  
  180.     /* Shut down the application */
  181.     ShutDown();
  182.  
  183.     /* Return the ANSI way */
  184.     return 0;
  185. }
  186.  
  187.  
  188. /******************************************************************************\
  189. * StartUp - Do whatever has to be done to initialize the application
  190. *
  191. * This routine is called after the heap is initialized to initialize the
  192. * application.  This involves initializing the toolbox, emergency memory,
  193. * loading up the menus, validating the current environment, and initializing
  194. * global variables.  If any errors occur while doing this, StartUp displays
  195. * an alert telling the user what the error was and then ExitToShell is called.
  196. * This is an unusual way to react to errors, and I only do it here because it’s
  197. * so early in execution that there really isn’t much else that can be done.
  198. *
  199. * See EmergMem.h in this application for details about emergency memory.
  200. \******************************************************************************/
  201.  
  202. static void StartUp()
  203. {
  204.     short        result;  /* Result of alert; ignored */
  205.     long         aeAttrs; /* AppleEvent attributes */
  206.     long         sfAttrs; /* Standard File attributes */
  207.     OSErr        error;
  208.     ExceptionRec exception;
  209.     long         msgType;
  210.     long         msgCode;
  211.  
  212.     if (ExceptionEntry( /*<*/&exception, /*<*/&msgType, /*<*/&msgCode ))
  213.     {
  214.         result = ShowAlert( kStopAlert, rOKAlertID, msgType, msgCode );
  215.         ExitToShell();
  216.     }
  217.  
  218.     /* Initialize the toolbox */
  219.     InitGraf( &thePort );
  220.     InitFonts();
  221.     InitWindows();
  222.     InitMenus();
  223.     TEInit();
  224.     InitDialogs( nil );
  225.  
  226.     /* Initialize emergency memory */
  227.     InitEmergMem();
  228.     if (FailLowMemory( 0 ))
  229.         Exception( &exception, rMemErrMessages, kMemErrAppOpenMsg );
  230.  
  231.     /* Initialize the menus */
  232.     error = StartMenus();
  233.     if (error == memFullErr || FailLowMemory( 0 ))
  234.         Exception( &exception, rMemErrMessages, kMemErrAppOpenMsg );
  235.     else if (error == resNotFound)
  236.         Exception( &exception, rResErrMessages, kResErrAppDamageMsg );
  237.     else if (error == dsSysErr)
  238.         Exception( &exception, rMiscErrMessages, kMiscErrUnknownMsg );
  239.  
  240.     /* Load and lock the disk-initialization package */
  241.     DILoad();
  242.  
  243.     /* See if WaitNextEvent is implemented */
  244.     gHasWNE = TrapExists( _WaitNextEvent );
  245.  
  246.     /* Check for the fancier capabilities */
  247.     error = Gestalt( gestaltAppleEventsAttr, /*<*/&aeAttrs );
  248.     if (error != noErr)
  249.         gHasAppleEvents = false;
  250.     else
  251.         gHasAppleEvents = btst( aeAttrs, gestaltAppleEventsPresent );
  252.     error = Gestalt( gestaltStandardFileAttr, /*<*/&sfAttrs );
  253.     if (error != noErr)
  254.         gHasCoolSF = false;
  255.     else
  256.         gHasCoolSF = btst( sfAttrs, gestaltStandardFile58 );
  257.  
  258.     /* Install the AppleEvent handler */
  259.     if (gHasAppleEvents)
  260.     {
  261.         error = AEInstallEventHandler( kCoreEventClass, kAEQuitApplication,
  262.                 (EventHandlerProcPtr)HandleAEquit, 0, false );
  263.         if (error == memFullErr || FailLowMemory( 0 ))
  264.             Exception( &exception, rMemErrMessages, kMemErrAppOpenMsg );
  265.         else if (error != noErr)
  266.             Exception( &exception, rMiscErrMessages, kMiscErrUnknownMsg );
  267.     }
  268. }
  269.  
  270.  
  271. /******************************************************************************\
  272. * ShutDown - Do whatever has to be done to shut down the application
  273. *
  274. * This routine is called when the application is about to shut down.  It calls
  275. * ExitGraphics and ExitPrinting to shut down Sarano graphics and printing.
  276. \******************************************************************************/
  277.  
  278. static void ShutDown()
  279. {
  280. }
  281.  
  282.  
  283. /******************************************************************************\
  284. * EventLoop - Main event loop for this application
  285. *
  286. * This is the main event loop of this application.  During every iteration of
  287. * the event loop, the menus are kept up-to-date.  Also, NoEmergMem is called to
  288. * detect whether the emergency memory was used.  If it was, then RecoverEmergMem
  289. * is called in an attept to get it back.  If it can’t, then some commands could
  290. * be disabled until the memory can be recovered.
  291. \******************************************************************************/
  292.  
  293. static void EventLoop()
  294. {
  295.     EventRecord anEvent;     /* An incoming event */
  296.     Boolean     gotEvent;    /* True if a non-null event was received */
  297.     WindowPtr   lastWindow;  /* Pointer to front window during last iteration */
  298.     WindowPtr   currWindow;  /* Pointer to the current front window */
  299.     WindowPtr   eventWindow; /* Window involved in an incoming event */
  300.     Byte        osEvtKind;   /* Kind of OSEvt; mouse-moved or suspend/resume */
  301.  
  302.     gWereInFront = true;
  303.     gQuitting = false;
  304.     gFixMenus = true;
  305.     lastWindow = nil;
  306.     InitCursor();
  307.  
  308.     /* We loop until gQuitting is true */
  309.     while (!gQuitting)
  310.     {
  311.         /* Try to reallocate emergency memory if it’s been used */
  312.         if (NoEmergMem())
  313.             RecoverEmergMem();
  314.  
  315.         /* Fix the menus to reflect current conditions */
  316.         currWindow = FrontWindow();
  317.         if (currWindow != lastWindow || gFixMenus)
  318.         {
  319.             FixMenus();
  320.             lastWindow = currWindow;
  321.             gFixMenus = false;
  322.         }
  323.  
  324.         /* It’s time to get and examine an event */
  325.         if (gHasWNE)
  326.             gotEvent = WaitNextEvent( everyEvent, /*<*/&anEvent,
  327.                     CalcSleepTime(), nil );
  328.         else
  329.         {
  330.             SystemTask();
  331.             gotEvent = GetNextEvent( everyEvent, /*<*/&anEvent );
  332.         }
  333.         if (gotEvent)
  334.             switch (anEvent.what)
  335.             {
  336.                 case mouseDown:
  337.                     DoMouseDown( &anEvent );
  338.                     break;
  339.                 case keyDown:
  340.                 case autoKey:
  341.                     DoKeyDown( &anEvent );
  342.                     break;
  343.                 case updateEvt:
  344.                     DoUpdateEvt( &anEvent );
  345.                     break;
  346.                 case diskEvt:
  347.                     DoDiskEvt( &anEvent );
  348.                     break;
  349.                 case activateEvt:
  350.                     DoActivateEvt( (WindowPtr)anEvent.message,
  351.                             anEvent.modifiers & activeFlag );
  352.                     break;
  353.                 case kHighLevelEvent:
  354.                     (void)AEProcessAppleEvent( &anEvent );
  355.                     break;
  356.                 case osEvt:
  357.                     osEvtKind = (anEvent.message >> 24) & 0x0FF;
  358.                     if (osEvtKind == suspendResumeMessage)
  359.                     {
  360.                         /* It’s a suspend/resume event; suspend or resume? */
  361.                         eventWindow = FrontWindow();
  362.                         if ((anEvent.message & 1) != 0)
  363.                         {
  364.                             /* Resume event; set the cursor and activate front window */
  365.                             InitCursor();
  366.                             if (eventWindow != nil)
  367.                                 DoActivateEvt( eventWindow, kBecomingActive );
  368.                             gWereInFront = true;
  369.                             }
  370.                         else
  371.                         {
  372.                             /* Suspend event; deactivate the front window */
  373.                             if (eventWindow != nil)
  374.                                 DoActivateEvt( eventWindow, !kBecomingActive );
  375.                             gWereInFront = false;
  376.                         }
  377.                     }
  378.                     break;
  379.             }
  380.     }
  381. }
  382.  
  383.  
  384. /******************************************************************************\
  385. * CalcSleepTime - Calculate the number of ticks for WaitNextEvent to sleep
  386. *
  387. * WaitNextEvent takes a parameter that specifies the number of ticks that this
  388. * application allows WaitNextEvent to service other open applications.  This is
  389. * just a guideline; the actual amount of time that WaitNextEvent takes could be
  390. * shorter or longer than our specification, depending on how heavy the system
  391. * load is and on how long other applications take.
  392. *
  393. * If the front window is a desk accessory window, CalcSleepTime returns 0 which
  394. * specifies that this application wants as much time as possible.  Under
  395. * MultiFinder, desk accessories are normally running in the DA Handler layer,
  396. * so this really doesn’t matter that much.  Under system software version 7.0,
  397. * desk accessories never run in our layer, so this code never gets executed.
  398. \******************************************************************************/
  399.  
  400. static long CalcSleepTime()
  401. {
  402.     long sleepTime; /* Number of ticks to sleep */
  403.  
  404.     if (IsDAWindow( FrontWindow() ))
  405.         sleepTime = 0;
  406.     else
  407.         sleepTime = kMaxSleepTime;
  408.  
  409.     return sleepTime;
  410. }
  411.  
  412.  
  413. /******************************************************************************\
  414. * DoMouseDown - Mouse-down event dispatcher
  415. *
  416. * When a mouseDown event is received in the main event loop, this routine is
  417. * called to determine which area on the screens the mouseDown was, and to
  418. * dispatch to the appropriate routine to handle mouseDown events in that area.
  419. * The mouseDown event is passed in the anEvent parameter.
  420. *
  421. * See MenuHandler.h for routines that handle mouse-down events in the menu bar.
  422. \******************************************************************************/
  423.  
  424. static void DoMouseDown(
  425.     EventRecord *anEvent) /* Contains mouse-down event */
  426. {
  427.     short     clickArea;   /* Area of the screen that was clicked */
  428.     WindowPtr eventWindow; /* Pointer the clicked window, if any */
  429.  
  430.     /* Find clicked area of screen or window */
  431.     clickArea = FindWindow( anEvent->where, /*<*/&eventWindow );
  432.  
  433.     /* Jump to mouseDown-handling routine appropriate for screen area */
  434.     switch (clickArea)
  435.     {
  436.         case inMenuBar:
  437.             DoMenuChoice( MenuSelect( anEvent->where ) );
  438.             break;
  439.         case inSysWindow:
  440.             SystemClick( anEvent, eventWindow );
  441.             break;
  442.         case inContent:
  443.             DoContentClick( anEvent, eventWindow );
  444.             break;
  445.         case inDrag:
  446.             DoWindowDrag( anEvent, eventWindow );
  447.             break;
  448.         case inGrow:
  449.             DoWindowGrow( anEvent, eventWindow) ;
  450.             break;
  451.         case inGoAway:
  452.             DoWindowClose( anEvent, eventWindow );
  453.             break;
  454.         default:
  455.             break;
  456.     }
  457. }
  458.  
  459.  
  460. /******************************************************************************\
  461. * DoKeyDown - Key-down event dispatcher
  462. *
  463. * When a keyDown or autoKey event is received in the main event loop, this
  464. * routine is called to determine whether key is a command-key equivalent for a
  465. * menu item or not.  If the command key isn’t down, then the key stroke is
  466. * ignored.  Otherwise, MenuKey is called to get the menu ID and item number
  467. * of the menu item that corresponds to the command key, if any.  Then
  468. * DoMenuChoice is called to dispatch to the appropriate routine for the chosen
  469. * menu item.  The keyDown or autoKey event is passed in anEvent.
  470. \******************************************************************************/
  471.  
  472. static void DoKeyDown(
  473.     EventRecord *anEvent) /* Contains the key-down event */
  474. {
  475.     char theKey; /* ASCII code of key that was pressed */
  476.  
  477.     /* Get the ASCII code of the pressed key */
  478.     theKey = anEvent->message & charCodeMask;
  479.  
  480.     /* If anEvent was keyDown and command key was down, it’s menu command */
  481.     if (anEvent->what == keyDown && (anEvent->modifiers & cmdKey))
  482.         DoMenuChoice( MenuKey( theKey ) );
  483. }
  484.  
  485.  
  486. /******************************************************************************\
  487. * DoDiskEvt - Handle a disk-insert event
  488. *
  489. * This routine is called whenever this application receives an event indicating
  490. * that a disk was inserted.  If the disk can’t be mounted, the message field of
  491. * the event reflects the error, and we call DIBadMount to allow the user to
  492. * format the disk.
  493. \******************************************************************************/
  494.  
  495. static void DoDiskEvt(
  496.     EventRecord *anEvent) /* Disk-insert event */
  497. {
  498.     Point cornerPoint; /* Top-left corner of DIBadMount alert */
  499.  
  500.     if (hiWord( anEvent->message ) != noErr)
  501.     {
  502.         SetPt( /*<*/&cornerPoint, kSysAlertLeft, kSysAlertTop );
  503.         (void)DIBadMount( cornerPoint, anEvent->message );
  504.     }
  505. }
  506.  
  507.  
  508. /******************************************************************************\
  509. * Private: HandleAEquit - Handler for 'quit' AppleEvent
  510. *
  511. * This is the AppleEvent handler for the 'quit' AppleEvent as passed in the
  512. * quitAppleEvent parameter by the AppleEvent Manager.  The DoQuit routine is
  513. * called which causes this application to quit at the start of the next
  514. * iteration of the main event loop.
  515. *
  516. * Though the quit AppleEvent doesn’t contain any parameters, the standard thing
  517. * to do in reaction to any AppleEvent is to check to see if there are any
  518. * required parameters in the AppleEvent that this routine doesn’t recognise.
  519. * DoneRequiredParms checks for this condition and returns an error if there are
  520. * in fact required parameters in the AppleEvent or if some other error occurs
  521. * during the check.
  522. \******************************************************************************/
  523.  
  524. static pascal OSErr HandleAEquit(
  525.     AppleEvent *quitAppleEvent, /* Contains the ‘quit’ AppleEvent */
  526.     AppleEvent *reply,          /* Returns reply; ignored */
  527.     long       handlerRefCon)   /* Application-defined parameter; ignored */
  528. {
  529. #pragma unused(reply,handlerRefCon)
  530.     OSErr error;
  531.  
  532.     /* quit AE has no parms, but check in case the client requires any */
  533.     error = DoneRequiredParams( quitAppleEvent );
  534.     if (error == noErr)
  535.         /* No extra parameters; handle Quit command */
  536.         DoQuit();
  537.  
  538.     return error;
  539. }
  540.  
  541.  
  542. /******************************************************************************\
  543. * DoneRequiredParams - Done processing required params; OK?
  544. *
  545. * DoneRequiredParams checks to see if the AppleEvent specified by the
  546. * anAppleEvent parameter has any required parameters that we haven’t yet
  547. * processed.  If there aren’t any left, then noErr is returned.  If there are
  548. * required parameters that haven’t been processed yet, then errAEEventNotHandled
  549. * is returned.  If any other errors occur, then that error code is returned.
  550. \******************************************************************************/
  551.  
  552. static OSErr DoneRequiredParams(
  553.     AppleEvent *anAppleEvent) /* AppleEvent being checked */
  554. {
  555.     DescType typeCode;   /* Type of AppleEvent attribute found; ignored */
  556.     Size     actualSize; /* Actual size of parameters; ignored */
  557.     OSErr    error;
  558.  
  559.     /* Are there any required parameters in AppleEvent we didn’t process? */
  560.        error = AEGetAttributePtr(
  561.                anAppleEvent,
  562.             keyMissedKeywordAttr,
  563.             typeWildCard,
  564.             /*<*/&typeCode,
  565.             nil,
  566.             0,
  567.             /*<*/&actualSize );
  568.     if (error == errAEDescNotFound)
  569.         /* No required parameters left, so no error */
  570.         error = noErr;
  571.     else if (error == noErr)
  572.         /* There was at least one required parameter we didn’t process */
  573.         error = errAEEventNotHandled;
  574.  
  575.     return error;
  576. }
  577.  
  578.  
  579. /******************************************************************************\
  580. * Public: DoQuit
  581. *
  582. * Each open window is checked to see what kind it is.  If a window is a
  583. * Document window, DoCloseDoc is called to close it.  If the window is a
  584. * desk accessory’s window, then CloseDeskAcc is called to close it.  This
  585. * process continues until all windows are closed.  Then the gQuitting global
  586. * variable is set to true, terminating the main event loop.
  587. \******************************************************************************/
  588.  
  589. void DoQuit()
  590. {
  591.     WindowPtr aWindow; /* Pointer to each window in the window list */
  592.  
  593.     aWindow = FrontWindow();
  594.  
  595.     /* Keep closing a window until there are no windows left */
  596.     while (aWindow != nil)
  597.     {
  598.         if (IsDAWindow( aWindow ))
  599.             CloseDeskAcc( ((WindowPeek)aWindow)->windowKind );
  600.         else
  601.             CloseWindow( aWindow );
  602.         aWindow = FrontWindow();
  603.     }
  604.  
  605.     /* Tell the main event loop that we’re done */
  606.     gQuitting = true;
  607. }
  608.  
  609.  
  610. /******************************************************************************\
  611. * Public: IsDAWindow
  612. *
  613. * The windowKind field of any window belonging to a desk accessory is negative,
  614. * so that’s how IsDAWindow decides whether a window belongs to a desk accessory
  615. * or not.
  616. \******************************************************************************/
  617.  
  618. Boolean IsDAWindow(
  619.     WindowPtr aWindow) /* Pointer to the window being tested */
  620. {
  621.     if (aWindow == nil)
  622.         return false;
  623.     else
  624.         return ((WindowPeek)aWindow)->windowKind < 0;
  625. }
  626.  
  627.  
  628. /******************************************************************************\
  629. * Private: DoWindowDrag - Allow the user to drag a window around
  630. *
  631. * When it’s been detected that the user clicked in the title bar of a window,
  632. * DoWindowDrag is called.  It allows the user to drag a window over the entire
  633. * desktop area, and the window is moved to wherever the user let it go.  Windows
  634. * behind the front window can be dragged as well, unless the front window is a
  635. * modal dialog box.
  636. *
  637. * The mouseDown event that turned out to be a request to drag the window is
  638. * passed in the anEvent parameter.  A pointer to the window whose title bar got
  639. * clicked is passed in clickedWindow.
  640. *
  641. * A rectangle that covers all screen can be retrieved from the desktop region’s
  642. * rgnBBox.  The desktop region can be retrieved by calling GetGrayRgn.
  643. \******************************************************************************/
  644.  
  645. static void DoWindowDrag(
  646.     EventRecord *anEvent,      /* Mouse-down event in the title bar */
  647.     WindowPtr   clickedWindow) /* Pointer to the window that was clicked */
  648. {
  649.     Rect dragBounds; /* Window can be dragged over this rectangle */
  650.  
  651.     /* (**GetGrayRgn()).rgnBBox covers the desktop over all screens */
  652.     dragBounds = (**GetGrayRgn()).rgnBBox;
  653.     DragWindow( clickedWindow, anEvent->where, &dragBounds );
  654. }
  655.  
  656.  
  657. /******************************************************************************\
  658. * Private: DoWindowGrow - Handle a mouse click in the grow box of a window
  659. *
  660. * When it’s been detected that the user clicked in the grow box of a window,
  661. * DoWindowGrow is called.  It allows the user to change the size of the clicked
  662. * window.
  663. *
  664. * The mouseDown event that turned out to be a request to resize the window is
  665. * passed in the anEvent parameter.  A pointer to the window whose grow box got
  666. * clicked is passed in clickedWindow.
  667. \******************************************************************************/
  668.  
  669. static void DoWindowGrow(
  670.     EventRecord *anEvent,      /* Mouse-down event in the title bar */
  671.     WindowPtr   clickedWindow) /* Pointer to the window that was clicked */
  672. {
  673.     /* Have the window react to the resize */
  674.     if (IsPictDocWindow( clickedWindow ))
  675.         GrowPictDoc( clickedWindow, anEvent );
  676. }
  677.  
  678.  
  679. /******************************************************************************\
  680. * Private: DoContentClick - Handle a click in a window
  681. *
  682. * When it’s been detected that the user clicked in the content region of a
  683. * window, DoContentClick is called.  This routine determines the kind of window
  684. * that was clicked and dispatches control to the routine that handles mouse
  685. * clicks in that kind of window.
  686. *
  687. * The mouseDown event that turned out to be a window content click is passed
  688. * in the anEvent parameter.  A pointer to the window whose content region got
  689. * clicked is passed in clickedWindow.
  690. *
  691. * As new kinds of windows are added to this application, this routine will have
  692. * to be able to detect the new kind of window and dispatch to the routine that
  693. * handles clicks in that kind of window.
  694. \******************************************************************************/
  695.  
  696. static void DoContentClick(
  697.     EventRecord *anEvent,      /* Mouse-down event in the window’s content */
  698.     WindowPtr   clickedWindow) /* Pointer to the window that was clicked */
  699. {
  700. #pragma unused(anEvent)
  701.     WindowPtr currWindow; /* Pointer to the current front window */
  702.  
  703.     currWindow = FrontWindow();
  704.  
  705.     /* Clicked window not in front; activate it */
  706.     if (currWindow != clickedWindow)
  707.         SelectWindow( clickedWindow );
  708.     else
  709.     {
  710.         if (IsPictDocWindow( clickedWindow ))
  711.             ClickPictDoc( clickedWindow, anEvent );
  712.     }
  713. }
  714.  
  715.  
  716. /******************************************************************************\
  717. * Public: DoUpdateEvt
  718. *
  719. * As new kinds of windows are added to this application, this routine will have
  720. * to be able to detect the new kind of window and dispatch to the routine that
  721. * handles update events in that kind of window.
  722. \******************************************************************************/
  723.  
  724. void DoUpdateEvt(
  725.     EventRecord *anEvent) /* Update event */
  726. {
  727.     WindowPtr eventWindow; /* Pointer to the window to update */
  728.  
  729.     /* Get a pointer to the window that needs an update */
  730.     eventWindow = (WindowPtr)anEvent->message;
  731.  
  732.     /* Update the window that needs it */
  733.     SetPort( eventWindow );
  734.     BeginUpdate( eventWindow );
  735.     if (IsPictDocWindow( eventWindow ))
  736.         DrawPictDoc( eventWindow );
  737.     EndUpdate( eventWindow );
  738. }
  739.  
  740.  
  741. /******************************************************************************\
  742. * Public: DoActivateEvt
  743. *
  744. * As new kinds of windows are added to this application, this routine will have
  745. * to be able to detect the new kind of window and dispatch to the routine that
  746. * handles activate events in that kind of window.
  747. \******************************************************************************/
  748.  
  749. void DoActivateEvt(
  750.     WindowPtr eventWindow,    /* Window being (de)activated */
  751.     Boolean   becomingActive) /* True if window is becoming activated */
  752. {
  753.     if (IsPictDocWindow( eventWindow ))
  754.         ActivatePictDoc( eventWindow, becomingActive );
  755. }
  756.  
  757.  
  758. /******************************************************************************\
  759. * Private: DoWindowClose - Handle a click in the close box of a window
  760. *
  761. * This routine should be called when the user clicks in the close box of the
  762. * window specified by eventWind.  The mouse is tracked until the user releases
  763. * the mouse button.  If the user released the mouse button while the mouse was
  764. * in the close box, then DoCloseDoc determines the kind of window that the user
  765. * clicked the close box on, and the routine that handles the closing of that
  766. * kind of window is called.  anEvent contains the mouse-down event that was
  767. * determined to be a mouse click in the window.
  768. *
  769. * As new kinds of windows are added to this application, this routine will have
  770. * to be able to detect the new kind of window and dispatch to the routine that
  771. * handles close requests for that kind of window.
  772. \******************************************************************************/
  773.  
  774. static void DoWindowClose(
  775.     EventRecord *anEvent,    /* Mouse-down event in the close box */
  776.     WindowPtr   eventWindow) /* Pointer to the window that was clicked */
  777. {
  778.     if (TrackGoAway( eventWindow, anEvent->where ))
  779.         if (IsPictDocWindow( eventWindow ))
  780.             DoClosePictDoc( eventWindow );
  781. }
  782.  
  783.  
  784. /******************************************************************************\
  785. * Public: ShowAlert
  786. *
  787. * To position the alert before it’s displayed, the ALRT resource is loaded
  788. * before it’s displayed, and its boundsRect is put into the proper position
  789. * through the CenterScreenRect routine.  Because this modifies the ALRT
  790. * resource in memory and because ALRT resources are normally purgeable, it must
  791. * be made unpurgeable until the alert is dismissed.
  792. \******************************************************************************/
  793.  
  794. short ShowAlert(
  795.     short alertType,    /* Type of alert to display */
  796.     short buttonOption, /* Button options for alert */
  797.     short messageClass, /* Class of message to display in alert */
  798.     short messageIndex) /* Index of message to display in alert */
  799. {
  800.     Str255     aMessage;    /* Contents of message to place in alert */
  801.     AlertTHndl alertHandle; /* Handle to the 'ALRT' resource for this alert */
  802.     Rect       alertRect;   /* Rectangle of alert */
  803.     short      itemHit;     /* Item number of clicked item */
  804.     SignedByte savedState;  /* Saves state alertHandle */
  805.  
  806.     /* Put the specified message into the dialog parameter text */
  807.     if (messageIndex != 0)
  808.     {
  809.         GetIndString( /*<*/aMessage, messageClass, messageIndex );
  810.         ParamText( aMessage, "\P", "\P", "\P" );
  811.     }
  812.  
  813.     /* Show the stop alert */
  814.     InitCursor();
  815.  
  816.     /* Center and display the alert */
  817.     alertHandle = (AlertTHndl)Get1Resource( 'ALRT', buttonOption );
  818.     if (alertHandle != nil)
  819.     {
  820.         /* Must make alert unpurgeable because we’re modifying it in memory */
  821.         savedState = HGetState( (Handle)alertHandle );
  822.         HNoPurge( (Handle)alertHandle );
  823.  
  824.         /* Put the rectangle of the alert into alert position */
  825.         alertRect = (**alertHandle).boundsRect;
  826.         PositionScreenRect( /*◊*/&alertRect, kMainScreenPos, kAlertPos,
  827.                 nil, 0, 0 );
  828.         (**alertHandle).boundsRect = alertRect;
  829.  
  830.         /* Present the alert */
  831.         if (alertType == kGenericAlert)
  832.             itemHit = Alert( buttonOption, nil );
  833.         else if (alertType == kNoteAlert)
  834.             itemHit = NoteAlert( buttonOption, nil );
  835.         else if (alertType == kCautionAlert)
  836.             itemHit = CautionAlert( buttonOption, nil );
  837.         else if (alertType == kStopAlert)
  838.             itemHit = StopAlert( buttonOption, nil );
  839.  
  840.         /* Restore the state of alertHandle */
  841.         HSetState( (Handle)alertHandle, savedState );
  842.     }
  843.  
  844.     return itemHit;
  845. }
  846.  
  847.  
  848. /******************************************************************************\
  849. * Public: TrapExists
  850. *
  851. * Traps with trap word of $AAXX or $ABXX are treated as being identical to $A8XX
  852. * and $A9XX if Color QuickDraw isn’t implemented, so we check for this case
  853. * first.  We explicitly check to see if the trap word has a value greater than
  854. * the largest possible trap word on this machine.  If it is, then the trap is
  855. * automatically considered to be unimplemented.
  856. \******************************************************************************/
  857.  
  858. Boolean TrapExists(
  859.     short theTrap) /* Trap word being tested */
  860. {
  861.     TrapType theTrapType; /* The trap type of theTrap */
  862.  
  863.     /* If it’s a CQD trap but the trap table is too small, assume unimp. */
  864.     theTrapType = GetTrapType( theTrap );
  865.     if ((theTrapType == ToolTrap) && ((theTrap &= 0x07FF) >=
  866.             MaxToolboxTrap()))
  867.         theTrap = _Unimplemented;
  868.  
  869.     /* Return true if trap is implemented */
  870.     return NGetTrapAddress( _Unimplemented, ToolTrap ) !=
  871.             NGetTrapAddress( theTrap, theTrapType );
  872. }
  873.  
  874.  
  875. /******************************************************************************\
  876. * Private: MaxToolboxTrap - Determine max trap number available
  877. *
  878. * Depending upon whether Color QuickDraw is implemented, the maximum trap number
  879. * is either $0200 or $0400.  This routine tests to see which is the case by
  880. * testing _InitGraf (trap $A86E) against trap $AA6E.  If the trap table is the
  881. * bigger one, trap $AA6E always points either to Unimplemented or some other
  882. * trap.  If the trap table is the smaller one, then $AA6E evaluates to the same
  883. * trap as _InitGraf.  by comparing the address of the InitGraf trap against the
  884. * address of the $AA6E trap, we can determine whether the trap table is the
  885. * bigger one or the smaller one.  If we have the bigger trap table, then $0400
  886. * is returned.  If it’s the smaller trap table, then $0200 is returned.
  887. *
  888. * Some of you might think that it’s be a lot simpler by testing to see whether
  889. * Color QuickDraw is implemented or not.  Actually, I kind of think so too, but
  890. * there are changes to the system software version 7.0 trap dispatcher that
  891. * might make that test invalid, so I don’t know.  I didn’t write this, I just
  892. * use it.
  893. \******************************************************************************/
  894.  
  895. static short MaxToolboxTrap()
  896. {
  897.     if (NGetTrapAddress( _InitGraf, ToolTrap ) ==
  898.             NGetTrapAddress(0xAA6E, ToolTrap))
  899.         return 0x0200;
  900.     else
  901.         return 0x0400;
  902. }
  903.  
  904.  
  905. /******************************************************************************\
  906. * Private: GetTrapType - Determine whether a trap is OS trap or Toolbox trap
  907. *
  908. * This routine tests to see whether the trap specified by theTrap is an
  909. * operating system trap or a toolbox trap.  Operating system trap words begin
  910. * with $A0 or $A1 while toolbox traps begin with $A8, $A9, $AA, or $AB.  By
  911. * simply testing bit 11 of the trap word, we can determine which kind of trap
  912. * theTrap is.  If it’s an operating system trap, then OSTrap is returned.  If
  913. * it’s a toolbox trap, then ToolTrap is returned.
  914. \******************************************************************************/
  915.  
  916. static TrapType GetTrapType(
  917.     short theTrap) /* Trap word being tested */
  918. {
  919.     /* OS traps start with A0 or A1, Toolbox traps with A8, A9, AA, or AB */
  920.     if ((theTrap & 0x0800) == 0)
  921.         return OSTrap;
  922.     else
  923.         return ToolTrap;
  924. }
  925.  
  926.  
  927. /******************************************************************************\
  928. * Public: FileSpecGet
  929. *
  930. \******************************************************************************/
  931.  
  932. Boolean FileSpecGet(
  933.     FileFilterProcPtr fileFilter, /* Pointer to routine to filter files */
  934.     short             numTypes,   /* Number of files types in typeList */
  935.     SFTypeList        typeList,   /* Type of files to offer */
  936.     StandardFileReply *retReply)  /* Returns information about file to get */
  937. {
  938.     DialogTHndl sfTemplate;  /* Template for Standard File dialog */
  939.     Rect        sfRect;      /* Rectangle of Standard File dialog */
  940.     SFReply     oldReply;    /* Old-style reply record */
  941.  
  942.     if (gHasCoolSF)
  943.         StandardGetFile( fileFilter, numTypes, typeList, /*<*/retReply );
  944.     else
  945.     {
  946.         /* Center the rectangle of the Standard File dialog */
  947.         sfTemplate = (DialogTHndl)GetResource( 'DLOG', getDlgID );
  948.         sfRect = (**sfTemplate).boundsRect;
  949.         PositionScreenRect( &sfRect, kMainScreenPos, kAlertPos,
  950.                 nil, 0, 0 );
  951.  
  952.         /* Present the Standard File dialog */
  953.         SFGetFile( topLeft( sfRect ), "\P", fileFilter, numTypes, typeList, nil,
  954.                 /*<*/&oldReply );
  955.  
  956.         /* Convert the old reply to a new reply record */
  957.         (void)ConvertOldToNewSFReply( &oldReply, retReply );
  958.     }
  959.     return retReply->sfGood;
  960. }
  961.  
  962.  
  963. /******************************************************************************\
  964. * Public: ConvertOldToNewSFReply
  965. *
  966. * GetWDInfo is used to convert the working directory reference number that’s
  967. * in the oldReply->vRefNum field to a real volume reference number and directory
  968. * ID so that these values can be stuffed into the new reply record’s FSSpec.
  969. \******************************************************************************/
  970.  
  971. OSErr ConvertOldToNewSFReply(
  972.     SFReply           *oldReply, /* Old reply record to be converted */
  973.     StandardFileReply *newReply) /* Returns the converted reply record */
  974. {
  975.     short   volRef;     /* Volume ref number (NOT WD ref num) of file */
  976.     long    dirID;      /* Directory ID of the file */
  977.     long    procID;     /* WD Proc ID; ignored */
  978.     FInfo   finderInfo; /* Finder info for a file; ignored */
  979.     Boolean replacing;  /* True if the specified file exists */
  980.     OSErr   error;
  981.  
  982.     /* Get the real volume reference number of directory ID of file */
  983.     error = GetWDInfo( oldReply->vRefNum, /*<*/&volRef,
  984.             /*<*/&dirID, /*<*/&procID );
  985.     if (error != noErr)
  986.         return error;
  987.  
  988.     /* Probe to see if the specified file exists */
  989.     error = HGetFInfo( volRef, dirID, oldReply->fName, /*<*/&finderInfo ); 
  990.     if (error == fnfErr)
  991.         replacing = false;
  992.     else if (error == noErr)
  993.         replacing = true;
  994.     else
  995.         return error;
  996.  
  997.     /* Fill out the new reply record */
  998.     newReply->sfGood = oldReply->good;
  999.     newReply->sfReplacing = replacing;
  1000.     newReply->sfType = oldReply->fType;
  1001.     newReply->sfFile.vRefNum = volRef;
  1002.     newReply->sfFile.parID = dirID;
  1003.     BlockMove( (Ptr)&oldReply->fName, (Ptr)&newReply->sfFile.name,
  1004.             oldReply->fName[0] + 1 );
  1005.     newReply->sfScript = iuSystemScript;
  1006.     newReply->sfFlags = 0;
  1007.     newReply->sfIsFolder = false;
  1008.     newReply->sfIsVolume = false;
  1009.     newReply->sfReserved1 = 0;
  1010.     newReply->sfReserved2 = 0;
  1011.  
  1012.     return noErr;
  1013. }
  1014.  
  1015.  
  1016. /******************************************************************************\
  1017. * Public: EqualFSSpec
  1018. *
  1019. * To compare names, I’m using EqualString with no case sensitivity, but with
  1020. * sensitivity to diacriticals.  This isn’t usually the recommended way of
  1021. * comparing strings, because the Script Manager has routines for comparing
  1022. * strings in a more sophisticated, localizable way.  But the File Manager uses
  1023. * _CmpString, which is the assembly language equivalent of EqualString, so
  1024. * that’s the way I must do things here.
  1025. \******************************************************************************/
  1026.  
  1027. Boolean EqualFSSpec(
  1028.     FSSpecPtr spec0, /* First FSSpec being compared */
  1029.     FSSpecPtr spec1) /* Second FSSpec being compared */
  1030. {
  1031.     return (spec0->vRefNum == spec1->vRefNum) &&
  1032.            (spec0->parID == spec1->parID) &&
  1033.            (EqualString(spec0->name, spec1->name, !kCaseSens, kDiacSens));
  1034. }
  1035.  
  1036.  
  1037. /******************************************************************************\
  1038. * Public: CmdPeriodEvent
  1039. *
  1040. * This routine uses the technique documented in Macintosh Technical Note #263
  1041. * to determine whether the event passed in the anEvent parameter contains a
  1042. * command-period event or not, regardless of the current keyboard layout.
  1043. *
  1044. * The problem that this routine solves is that some keyboards (mainly some
  1045. * European keyboards) require the shift key to be pressed to generate the
  1046. * period, but the command key turns off the shift key, making it impossible to
  1047. * see the period.  To fix this, this routine calls the KeyTrans routine which
  1048. * maps a virtual keycode and modifier keys to the ASCII code of the typed
  1049. * character.  The modifier keys passed to KeyTrans are the same as in the
  1050. * event record, but the command key modifier bit is stripped out.  This makes
  1051. * KeyTrans think the command key wasn’t held down, and so the influence of other
  1052. * modifier keys is unaffected.
  1053. \******************************************************************************/
  1054.  
  1055. Boolean CmdPeriodEvent(
  1056.     EventRecord *anEvent) /* Event being tested */
  1057. {
  1058.     long    lowChar;      /* Low character of keyInfo */
  1059.     long    highChar;     /* High character of keyInfo */
  1060.     Handle  hKCHR;        /* Handle to the currently-used KCHR */
  1061.     long    keyInfo;      /* Key information returned from KeyTrans */
  1062.     long    keyScript;    /* Script of the current keyboard */
  1063.     long    state;        /* State used for KeyTrans */
  1064.     short   virtualKey;   /* Virtual keycode of the character-generating key */
  1065.     short   keyCode;      /* Keycode of the character-generating key */
  1066.     Boolean gotCmdPeriod; /* True if detected command-. */
  1067.  
  1068.     gotCmdPeriod = false;
  1069.     if (anEvent->what == keyDown || anEvent->what == autoKey)
  1070.     {
  1071.         if (anEvent->modifiers & cmdKey)
  1072.         {
  1073.             /* Get the virtual keycode of the code-generating key */
  1074.             virtualKey = (anEvent->message & keyCodeMask) >> 8;
  1075.  
  1076.             /* Get a copy of the current KCHR */
  1077.             keyScript = GetScript( GetEnvirons( smKeyScript ), smScriptKeys);
  1078.             hKCHR = GetResource('KCHR', keyScript);
  1079.             if (hKCHR != nil)
  1080.             {
  1081.                 /* AND out the command key and OR in the virtualKey */
  1082.                 keyCode = (anEvent->modifiers & kMaskModifiers) | virtualKey;
  1083.  
  1084.                 /* Get key information */
  1085.                 state = 0;
  1086.                 keyInfo = KeyTrans( *hKCHR, keyCode, &state );
  1087.             }
  1088.             else
  1089.                 keyInfo = anEvent->message;
  1090.  
  1091.             /* Check both low and high bytes of keyInfo for period */
  1092.             lowChar = keyInfo & kMaskASCII2;
  1093.             highChar = (keyInfo & kMaskASCII1) >> 16;
  1094.             if (lowChar == '.' || highChar == '.')
  1095.                 gotCmdPeriod = true;
  1096.         }
  1097.     }
  1098.  
  1099.     return gotCmdPeriod;
  1100. }
  1101.  
  1102.  
  1103. /******************************************************************************\
  1104. * Public: FakeButtonHit
  1105. *
  1106. * HiliteControl is used to hilight and unhilight a button.
  1107. \******************************************************************************/
  1108.  
  1109. void FakeButtonHit(
  1110.     ControlHandle buttonControl) /* Handle to button whose click we’re faking */
  1111. {
  1112.     long lastTicks; /* TickCount at end of delay; ignored */
  1113.  
  1114.     HiliteControl( buttonControl, 1 );
  1115.     Delay( 6, &lastTicks );
  1116.     HiliteControl( buttonControl, 0 );
  1117. }
  1118.  
  1119.  
  1120. /******************************************************************************\
  1121. * NAME & SYNOPSIS:
  1122. * RestoreColorsPalette: Restore all screens to the default color table
  1123. *
  1124. * PARAMETERS:
  1125. * See ColorReset.h
  1126. *
  1127. * DEFINITION:
  1128. * See ColorReset.h
  1129. *
  1130. * DESCRIPTION:
  1131. * To change the color table of any screen using the Palette Manager, a window
  1132. * must be used.  But all we want to do is reset the color tables, not display a
  1133. * window.  The obvious solution is to make a very small, inconspicuous window
  1134. * that’s tough to notice, and that’s what RestoreColorsPalette does.  A 1 pixel
  1135. * by 1 pixel is created, and a 1-entry palette is made and attached to the
  1136. * window, just so that it has a palette that can be set to the right size and
  1137. * colors later.
  1138. *
  1139. * Each screen can have different depths, and each can be gray-scale or colors,
  1140. * so every screen has have its colors set individually.  Since all we have is a
  1141. * 1 pixel by 1 pixel window, there’s not much choice here anyway.  To run
  1142. * through each screen, the GDevice list is used.  The GDevice list is a linked
  1143. * list of GDevice records that the system maintains, and there’s one GDevice
  1144. * record for every screen that’s attached to a Macintosh.  Each screen’s GDevice
  1145. * can be used to find out the screen’s depth, and whether it’s set to Grays or
  1146. * Colors mode.  See the Graphics Device Manager chapter of Inside Macintosh
  1147. * Volume VI for details. GetDeviceList is used to find the first GDevice in the
  1148. * GDevice list, and GetNextDevice is used to get the next GDevice list the list.
  1149. *
  1150. * For each GDevice in the list, it’s first tested to see if it belongs to an
  1151. * active screen.  If it doesn’t, then we just ignore it and go to the next
  1152. * GDevice in the list.  If it does, then the GDevice’s PixMap is checked to see
  1153. * what the depth of the screen is.  This depth can be passed to the GetCTable
  1154. * routine (see the Color Manager chapter of Inside Macintosh Volume V for
  1155. * details about this routine) to get a color table filled with the default
  1156. * colors for the screen depth.  As of 32-Bit QuickDraw 1.0 and/or system
  1157. * software version 6.0.5, the color table of a screen is guaranteed to contain
  1158. * the highlight color, and if you add 64 to the pixel depth and pass the result
  1159. * to GetCTable, GetCTable returns a color table filled with the default colors
  1160. * including the highlight color, and so that’s what I pass to GetCTable for a
  1161. * screen set to Colors mode.  For gray-scale screens, you add 32 to the pixel
  1162. * depth to have GetCTable return a color table filled with the default gray-
  1163. * scale color table.
  1164. *
  1165. * I pass whatever color table GetCTable returns to CTab2Palette, and I use a
  1166. * usage mode of pmTolerant + pmExplicit.  This mode is just like pmTolerant, but
  1167. * it guarantees that the palette colors are put into the screen’s color table in
  1168. * the same order that they appear in the palette when that palette is activated.
  1169. * If you just use pmTolerant, the order of colors in the screen’s color table
  1170. * will likely be scrambled, so the screen has the default colors, but not in the
  1171. * default order.
  1172. *
  1173. * Once the palette is set up with the default colors for the screen we’re
  1174. * working on, the 1 pixel by 1 pixel window is moved to the extreme upper-left
  1175. * corner of the screen, then it’s shown and immediately hidden.  The moment the
  1176. * window is shown, the screen’s color table is filled with the default colors in
  1177. * the default order.  Then we move on to the next screen until all screens have
  1178. * been handled.
  1179. *
  1180. * RETURN VALUES:
  1181. * See ColorReset.h
  1182. \******************************************************************************/
  1183.  
  1184. void RestoreColorsPalette()
  1185. {
  1186.     WindowPtr     tinyWindow;    /* Pointer to tiny window */
  1187.     CTabHandle    defaultColors; /* Default color table for the screen */
  1188.     PaletteHandle tinyPalette;   /* Palette to express defaultColors */
  1189.     Rect          tinyRect;      /* Rectangle of tiny window */
  1190.     GDHandle      screenDevice;  /* Handle to each screen’s GDevice */
  1191.     Point         screenCorner;  /* Global coordinate of top-left of each screen */
  1192.     short         clutID;        /* ID of table of default colors */
  1193.  
  1194.     /* Make the tiny window for attaching our palette */
  1195.     SetRect( &tinyRect, 0, 0, 1, 1 );
  1196.     tinyWindow = NewCWindow(
  1197.             nil,
  1198.             &tinyRect,
  1199.             "\P",
  1200.             false,
  1201.             plainDBox,
  1202.             (WindowPtr)-1,
  1203.             false,
  1204.             0L );
  1205.  
  1206.     /* Make a palette; it’s just a placeholder for the moment */
  1207.     tinyPalette = NewPalette( 1, nil, pmTolerant + pmExplicit, 0 );
  1208.     SetPalette( tinyWindow, tinyPalette, false );
  1209.  
  1210.     /* Loop through each screen GDevice to reset its screen’s colors */
  1211.     screenDevice = GetDeviceList();
  1212.     while (screenDevice != nil)
  1213.     {
  1214.         if (TestDeviceAttribute( screenDevice, screenActive ))
  1215.         {
  1216.             /* Grab default color table for the screen */
  1217.             clutID = (**(**screenDevice).gdPMap).pixelSize;
  1218.             if (TestDeviceAttribute (screenDevice, gdDevType ))
  1219.                 clutID += 64;
  1220.             else
  1221.                 clutID += 32;
  1222.             defaultColors = GetCTable( clutID );
  1223.  
  1224.             /* Convert default screen colors to a tolerant palette */
  1225.             CTab2Palette( defaultColors, tinyPalette, pmTolerant + pmExplicit, 0 );
  1226.  
  1227.             /* Don’t need that clut any more */
  1228.             DisposeCTable( defaultColors );
  1229.  
  1230.             /* Move the tiny window into the upper left corner of the screen */
  1231.             screenCorner = topLeft( (**screenDevice).gdRect );
  1232.             MoveWindow( tinyWindow, screenCorner.h, screenCorner.v, false );
  1233.             ShowWindow( tinyWindow );
  1234.             HideWindow( tinyWindow );
  1235.         }
  1236.  
  1237.     /* Go to the next screen in the device list */
  1238.     screenDevice = GetNextDevice( screenDevice );
  1239.     }
  1240.  
  1241.     /* Get rid of the window and palette */
  1242.     DisposePalette( tinyPalette );
  1243.     DisposeWindow( tinyWindow );
  1244. }
  1245.  
  1246.  
  1247. /******************************************************************************\
  1248. * NAME & SYNOPSIS:
  1249. * RestoreColorsSlam: Restore all screens to the default color table
  1250. *
  1251. * PARAMETERS:
  1252. * See ColorReset.h
  1253. *
  1254. * DEFINITION:
  1255. * See ColorReset.h
  1256. *
  1257. * DESCRIPTION:
  1258. * 32-Bit QuickDraw 1.0 and system software version 6.0.5 introduced a new
  1259. * routine called RestoreDeviceClut which sets the color table of specific
  1260. * screens or all the screens to the default set of colors.  RestoreColorsSlam
  1261. * calls RestoreDeviceClut with a nil parameter, which restores the color table
  1262. * of all attached screens.  At this point, the screen could appear in strange
  1263. * colors because RestoreDeviceClut doesn’t cause update events to cause the
  1264. * screen to be redrawn in the new colors.  So, RestoreColorsSlam forces all the
  1265. * screens to be redrawn by calling the Window Manager routine, PaintBehind.
  1266. * This causes the entire desktop area and all windows to be redrawn.  The only
  1267. * part of the screen that isn’t guaranteed to be redrawn is the menu bar, so
  1268. * DrawMenuBar is called to make sure the menu bar is redrawn in the new colors.
  1269. *
  1270. * RETURN VALUES:
  1271. * See ColorReset.h
  1272. \******************************************************************************/
  1273.  
  1274. void RestoreColorsSlam()
  1275. {
  1276.     RestoreDeviceClut( nil );
  1277.     PaintBehind( nil, GetGrayRgn() );
  1278.     DrawMenuBar();
  1279. }
  1280.